﻿// //  ********************************************************************************
// //  Copyright (C) 2016 Sebastian Kenter. All rights reserved.
// // 
// //  Name    : MultiServerEngine | MasterServer | RegisterSubServerRequestHandler.cs
// //  Created : 2016 - 02 - 16 20:53
// //  Modified: 2016 - 02 - 20 12:33
// //  ********************************************************************************

using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Xml;
using ExitGames.Logging;
using NHibernate;
using Photon.SocketServer;
using ServerFramework.Implementation.Configuration;
using ServerFramework.Implementation.Database;
using ServerFramework.Implementation.Database.Domain;
using ServerFramework.Implementation.Handler;
using ServerFramework.Implementation.Operations.Request;
using ServerFramework.Implementation.Server;
using ServerFramework.Implementation.Telegram;
using ServerFramework.Interfaces.Server;
using ServerFramework.Interfaces.Telegram;
using TypeDefs;

namespace MasterServer.Handler.Request
{
    public class RegisterSubServerRequestHandler : ServerTelegramHandler
    {
        public override TelegramHandlerTypes HandlerType => TelegramHandlerTypes.Request;
        public override byte Code => (byte) OperationCodes.System;
        public override int? SubCode => (int?) OperationSubCodes.RegisterSubServer;

        private IServerPeerRegistry<IServerPeer> ServerPeerRegistry { get; }

        public RegisterSubServerRequestHandler(ILogger logger, IServerPeerRegistry<IServerPeer> serverPeerRegistry)
            : base(logger)
        {
            ServerPeerRegistry = serverPeerRegistry;
        }

        public override bool HandleTelegram(ITelegram telegram, IServerPeer serverPeer)
        {
            Logger.InfoFormat("Trying to handle telegram of type={0}, code={1}, sub-code={2}", telegram.Type,
                telegram.Code, telegram.SubCode);

            ServerPeer peer = serverPeer as ServerPeer;

            if (peer == null) return false;

            RegisterSubServerRequestOperation contract = new RegisterSubServerRequestOperation(peer.Protocol, telegram);

            if (!contract.IsValid)
            {
                string msg = contract.GetErrorMessage();
                Logger.ErrorFormat("Server peer register request invalid ({0})", msg);
                peer.SendTelegram(new ResponseTelegram(telegram.Code, telegram.SubCode, telegram.Parameters,
                    (short) ErrorCodes.InvalidOperation, msg));
            }

            ServerConfiguration configuration;

            DataContractSerializer dcs = new DataContractSerializer(typeof (ServerConfiguration));

            using (XmlReader reader = XmlReader.Create(new StringReader(contract.Configuration)))
            {
                configuration = (ServerConfiguration) dcs.ReadObject(reader);
            }

            Logger.InfoFormat("Valid register request received from server {0} on server {1}",
                (ServerTypes) contract.PeerType, peer.ServerType);

            peer.SetHandledOperations(configuration.HandledOperations);

            if (!ServerPeerRegistry.RegisterPeer((ServerTypes) contract.PeerType, peer)) return false;

            using (ISession session = SessionManager.OpenSession())
            {
                using (ITransaction transaction = session.BeginTransaction())
                {
                    var sp = (ServerPeer) serverPeer;

                    var speer = new ServerPeer_T
                               {
                                   Connected = 1,
                                   Localip = sp.LocalIP,
                                   Localport = sp.LocalPort,
                                   Localservertype = (int) sp.ServerType,
                                   Remoteip = sp.RemoteIP,
                                   Remoteport = sp.RemotePort,
                                   Remoteservertype = contract.PeerType,
                                   Peerid = sp.PeerId.ToString()
                               };

                    if (!session.QueryOver<ServerPeer_T>().List<ServerPeer_T>().Contains(speer))
                    {
                        session.Save(speer);
                    }

                    transaction.Commit();
                }

                session.Close();
            }

                peer.SendOperationResponse(
                    new OperationResponse(telegram.Code,
                        new Dictionary<byte, object>
                        {
                        {(byte) ParameterCodes.SubCode, telegram.SubCode},
                        {(byte) ParameterCodes.PeerType, (byte) peer.ServerType},
                        {(byte) ParameterCodes.PeerId, peer.PeerId.ToString()}
                        })
                    {
                        ReturnCode =
                            (short)
                            ErrorCodes.Ok
                    },
                    new SendParameters());
            return true;
        }
    }
}
